/**
 * 
 */
package server;

import java.net.*;
import java.io.*;
import java.util.TreeMap;

/**
 * @author peleg
 *
 */
public class FileServerApplication extends ServerApplication implements IServerApplication {
	/* ----------- private declerations ------------------------- */
	private static ClusterManagementModule myCMM;
	private static ConnectionInformation myConnectionInformation;
	private static TreeMap<Integer, SATaskContext> TaskContextDB;
	private static SATaskContext newTaskContext;
	private static boolean newTaskContextIsValid;
	private static InetAddress LocalAddr;
	private static DatagramSocket Socket;
	private static Logger LogFile;
	
	/* ------------ constant definitions ------------------------- */ 
	private static final int DGRAM_BUF_LEN = 4096; 
	private static final short DEFAULT_PORT_NUM = 2048;
	private static final String LOG_FILENAME = "ServerApp.log";
	
	
	/* ------------ function implementations --------------------- */
	public void LogEntry(String ModuleName, String Entry){
		LogFile.AddEntry(ModuleName, Entry);		
	}
				
	/* (non-Javadoc)
	 * @see server.IServerApplication#ReceiveNewTaskId(int)
	 */
	public void ReceiveNewTaskId(int TaskId) throws SAExn_UnexpectedTaskId, SAExn_TaskIdAlreadyPresent {
		if (!newTaskContextIsValid){
			SAExn_UnexpectedTaskId excpt = new SAExn_UnexpectedTaskId(TaskId);
			throw excpt; 
		}
		if (TaskContextDB.containsKey(TaskId)){
			System.err.println("ERROR: TaskId is already in the SA task database !");
			SAExn_TaskIdAlreadyPresent excpt = new SAExn_TaskIdAlreadyPresent(TaskId);
			throw excpt;			
		}
		TaskContextDB.put(TaskId, newTaskContext);
		newTaskContextIsValid = false;
		// TODO create a new thread for the task
		return;
	}

	/* (non-Javadoc)
	 * @see server.IServerApplication#ReconstructTaskContext(server.TaskContext, server.IncramentalTaskContext)
	 */
	public SATaskContext ReconstructTaskContext(SATaskContext OldContext,
			IncramentalTaskContext Delta) {
		// TODO Auto-generated method stub
		return null; // TODO figure out how I can cast Delta to TaskContext type;
	}
	
	public FileServerApplication(){
//		 prepeare socket
		LogFile = new Logger();
		try{
			LogFile.OpenLog(LOG_FILENAME);
		}
		catch (FileNotFoundException e){
			System.err.println("Error opening log file !");
			return;// TODO: in order to quit the app, do I need to throw some kind of exception ?
		}
		try {
		    Socket = new DatagramSocket(DEFAULT_PORT_NUM);
		} catch (SocketException e) {
			System.err.println("Error creating datagram socket");
		    e.printStackTrace();
            return;
		}
				
		// obtain local IP address to report to CMM
		try {
			LocalAddr = InetAddress.getLocalHost();
		}
		catch (IOException e) {
 			System.err.println("Error obtaining local IP address");
 			System.err.println(e);
 			return;
		}
		myConnectionInformation = new ConnectionInformation(LocalAddr, DEFAULT_PORT_NUM);

		/* create the CMM */
		myCMM = new ClusterManagementModule(this, myConnectionInformation);
	}

	/* (non-Javadoc)
	 * @see server.IServerApplication#StartServicingTask(int, server.TaskContext)
	 */
	public void StartServicingTask(int TaskId, TaskContext Task) {
		// TODO implement when we add support for task migration
	}

	/* (non-Javadoc)
	 * @see server.IServerApplication#StopServicingTask(int)
	 */
	public void StopServicingTask(int TaskId) {
		// TODO implement when we add support for task migration
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TaskContextDB = new TreeMap<Integer, SATaskContext>();
		newTaskContext = new SATaskContext();
		newTaskContextIsValid = false;
		byte[] buf = new byte[DGRAM_BUF_LEN];
		DatagramPacket packet = new DatagramPacket(buf, buf.length);
		ConnectionInformation newConn;
		
						
		while (true){
			try{
				Socket.receive(packet);
			}
			catch (IOException e) {
				System.err.println("Error receiving on server socket");
			}
			
			if (buf[0] == PacketType.NEW_SESSION.ordinal()){	// here we assume each incoming packet will contain a PacketType
				newTaskContext.setProgress(0);
				newTaskContext.setFile((int)(buf[1]));
				newConn.putIP(packet.getAddress());
				newConn.putPort((short)packet.getPort());
				newTaskContext.setConnInfo(newConn);
				newTaskContextIsValid = true;
				myCMM.NewTask(newTaskContext);  // TODO resolve how I can make NewTask get SATaskContext types
			}
			else {	// TODO: else - find who sent this packet and give the message to the appropriate thread
					// this is neccesary only if we want to enable the clients to send messages to their server-threads
				
			}
		}
		

	}

	public void AddLogEntry(String ModuleName, String Entry) {
		// TODO Auto-generated method stub
		
	}

}
